import { execSync, exec, fork, ChildProcess } from "child_process";
let childCount = 0;
export namespace ShellToolDS {
  export type ShellError = {};
  export type ShellResult = { commond: string, buffer: Buffer, result: string, length: number, error: any, usedTime: number };
  export type ShellToolsOptions = { cwd?: string, timeout?: number } | {};
}

export class ShellTool {
  options !: ShellToolDS.ShellToolsOptions;
  constructor(options: ShellToolDS.ShellToolsOptions = {}) {
    this.options = options;
  }
  shellSync(commond: string): ShellToolDS.ShellResult {
    const startTime: number = (new Date()).valueOf();
    let error = null, buffer = Buffer.from([]);
    console.log("\n@shellSync", commond, "\n");
    try {
      buffer = execSync(commond);
    } catch (e) {
      error = e;
    }
    const result = buffer.toString();
    const length: number = result.length;
    const usedTime: number = (new Date()).valueOf() - startTime;
    return { usedTime, error, result, length, buffer, commond };
  }
  getFrokShellTool() {
    console.log("getFrokShellTool", childCount)
    if (++childCount > 24) console.log("FROK TOO MUCH");
    let e = fork('./dist/frok/shellSync.js');

    return new FrokShellTool(e);
  }
  async shell(commond: string): Promise<ShellToolDS.ShellResult> {
    let e = fork('./dist/frok/shell.js');
    return await new Promise(reslove => {
      e.on('message', (arg: ShellToolDS.ShellResult) => reslove((e.kill(), arg)));
      e.send(commond);
    });
  }
}
export class FrokShellTool {
  child: ChildProcess;
  constructor(child: ChildProcess) {
    this.child = child;
  }
  async shellSync(commond: string): Promise<ShellToolDS.ShellResult> {
    return await new Promise(reslove => {
      this.child.on('message', (arg: { arg: ShellToolDS.ShellResult, commond: string }) => arg.commond === commond ? reslove(arg.arg) : null);
      this.child.send(commond);
    });
  }
  exit() { this.child.kill() }
}


export default new ShellTool();
